package com.cwx.mychat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cwx.mychat.entity.constant.CodeConstant;
import com.cwx.mychat.entity.dto.TokenUserInfoDto;
import com.cwx.mychat.entity.enums.*;
import com.cwx.mychat.entity.po.*;
import com.cwx.mychat.entity.vo.MessageSendVo;
import com.cwx.mychat.entity.vo.SearchUserVo;
import com.cwx.mychat.entity.vo.UserInfoVO;
import com.cwx.mychat.exception.BusinessException;
import com.cwx.mychat.mappers.*;
import com.cwx.mychat.service.*;
import com.cwx.mychat.utils.R;
import com.cwx.mychat.utils.common.CommonUtil;
import com.cwx.mychat.utils.stringUtils.StringUtil;
import com.cwx.mychat.websocket.message.SendMessageHandler;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class UserContactApplyServiceImpl extends ServiceImpl<UserContactApplyMapper, UserContactApply> implements UserContactApplyService {


    @Autowired
    private UserContactApplyMapper userContactApplyMapper;

    @Autowired
    private UserContactMapper userContactMapper;

    @Autowired
    private UserContactService userContactService;

    @Autowired
    private ChatSessionUserService chatSessionUserService;

    @Autowired
    private UserContactCategoryService userContactCategoryService;

    @Autowired
    private GroupInfoMapper groupInfoMapper;

    @Autowired
    private SendMessageHandler sendMessageHandler;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;


    @Override
    @Transactional(rollbackFor = BusinessException.class)
    public R addContact(String verifyInfo, String remark, Map group, Boolean permission, String receiveId, String helloMsg) throws BusinessException {
        //获取当前用户信息
        TokenUserInfoDto tokenUserInfoDto = CommonUtil.getSecurityContext();
        UserContactTypeEnum typeEnum = UserContactTypeEnum.getPrefix(receiveId);
        if(typeEnum == null){
            throw new BusinessException(ExceptionBizCodeEnum.USER_ID_FORMAT_EXCEPTION);
        }
        //查询分组
        String groupId = null;
        UserContactCategory userContactCategory = null;
        if(group != null){
            //处理分组
            try{
                userContactCategory = CommonUtil.mapToObject(group, UserContactCategory.class);
                if(userContactCategory.getCategoryId() != null){
                    UserContactCategory userContactCategory1 = userContactCategoryService.getById(userContactCategory.getCategoryId());
                    if(userContactCategory1 != null){
                        groupId = userContactCategory1.getCategoryId();
                    }else{
                        groupId = createCategory(tokenUserInfoDto.getUserId(), userContactCategory);
                        if(groupId == null){
                            log.error("添加分组失败");
                        }
                    }
                }else{
                    log.error("添加分组失败");
                }
            }catch (Exception e){
                log.error("分组失败", e);
            }
        }
        //查询对方是否已经是好友是否拉黑自己
        UserContact userContact = userContactMapper.selectOne(tokenUserInfoDto.getUserId(), receiveId);
        if(userContact != null && userContact.getStatus().equals(UserContactStatusEnum.FRIEND.getStatus())){
            return R.error("对方已是你的好友");
        }
        if(userContact != null && userContact.getStatus().equals(UserContactStatusEnum.BE_BLOCKED.getStatus())){
            return R.error("对方已拉黑你，无法添加");
        }
        Integer joinType;
        String receiveUserId = receiveId;
        //如果是群组
        GroupInfo groupInfo = null;
        UserInfo userInfo = null;
        if(UserContactTypeEnum.GROUP == typeEnum){
            groupInfo = groupInfoMapper.selectById(receiveId);
            if(groupInfo == null || groupInfo.getStatus().equals(GroupStatusEnum.DISSOLVE.getStatus())){
                return R.error("群组不存在或已解散");
            }
            receiveUserId = groupInfo.getGroupOwnerId();
            joinType = groupInfo.getJoinType();
        }else{
            userInfo = userInfoMapper.selectById(receiveId);
            if(userInfo == null){
                return R.error("用户不存在");
            }
            joinType = userInfo.getJoinType();
        }
        //直接加入并记录申请
        boolean join = false;
        if(joinType.equals(JoinTypeEnum.JOIN.getType())){
            //直接加入,添加联系人
            addContact(tokenUserInfoDto.getUserId(), receiveId,
                    receiveUserId, verifyInfo, remark,
                    UserContactTypeEnum.GROUP == typeEnum? UserContactTypeEnum.GROUP.getType() : UserContactTypeEnum.USER.getType(),
                    userContact);
            //添加会话
            int session = chatSessionUserService.addSession(tokenUserInfoDto,
                        groupInfo != null ? groupInfo : userInfo,
                        helloMsg,
                        UserContactTypeEnum.GROUP == typeEnum? UserContactTypeEnum.GROUP.getType() : UserContactTypeEnum.USER.getType());
            if(session <= 0){
                throw new BusinessException(ExceptionBizCodeEnum.SESSION_ADD_FAILED);
            }
            if(permission != null && permission){
                //TODO 处理只聊天不看动态
            }
            if(groupId != null){
                //添加到分组
                userContactCategoryService.addGroup(groupId, tokenUserInfoDto.getUserId(), receiveId);
            }
            //发送消息通知好友
            sendNotice(helloMsg, tokenUserInfoDto, typeEnum, groupInfo, userInfo);
            join = true;
        }
        //查询是否存在申请信息
        UserContactApply userContactApply = userContactApplyMapper.selectOne(new LambdaQueryWrapper<UserContactApply>()
                .eq(UserContactApply::getApplyUserId, tokenUserInfoDto.getUserId())
                .eq(UserContactApply::getReceiveUserId, receiveId));
        if(userContactApply != null){
            userContactApply.setLastApplyTime(new Date());
            userContactApply.setApplyInfo(verifyInfo);
            userContactApply.setHelloMsg(helloMsg);
            if(join){
                userContactApply.setStatus(UserContactApplyStatusEnum.AGREED.getStatus());
            }
            if (permission != null) {
                userContactApply.setPermission(permission.toString());
            }
            userContactApply.setContactId(groupId);
            //更新申请信息
            userContactApplyMapper.updateById(userContactApply);
            //TODO 发消息通知好友

            if(userContactApply.getStatus().equals(UserContactApplyStatusEnum.DECLINED.getStatus())){
                return R.error("对方已拒绝你的申请，无法添加");
            }
            if(userContactApply.getStatus().equals(UserContactApplyStatusEnum.AGREED.getStatus())){
                //对方已同意添加自己
                return R.ok("对方已同意");
            }
            if(userContactApply.getStatus().equals(UserContactApplyStatusEnum.BLOCKED.getStatus())){
                return R.error("对方已拉黑你，无法添加");
            }
        }else {
            //增加申请列表
            userContactApply = new UserContactApply();
            userContactApply.setCreateTime(new Date());
            userContactApply.setLastApplyTime(new Date());
            userContactApply.setApplyUserId(tokenUserInfoDto.getUserId());
            userContactApply.setReceiveUserId(receiveId);
            userContactApply.setContactId(receiveUserId);
            userContactApply.setContactType(UserContactTypeEnum.USER == typeEnum ? UserContactTypeEnum.USER.getType(): UserContactTypeEnum.GROUP.getType());
            userContactApply.setStatus(UserContactApplyStatusEnum.PENDING.getStatus());
            userContactApply.setApplyInfo(verifyInfo);
            userContactApply.setRemark(remark);
            userContactApply.setCategoryId(groupId);
            userContactApply.setHelloMsg(helloMsg);
            if (permission != null) {
                userContactApply.setPermission(permission.toString());
            }
            userContactApplyMapper.insert(userContactApply);
            //TODO 发消息通知加好友
            Map<String, Object> notice = new HashMap<>();
        }
        if(join){
            Map<String, Object> map = new HashMap<>();
            map.put("type", SearchUserVo.Type.FRIEND.getType());
            String chatSessionIdUser = CommonUtil.getChatSessionIdUser(new String[]{tokenUserInfoDto.getUserId(), receiveId});
            String contactName = UserContactTypeEnum.USER == typeEnum ? userInfo.getNickName() : groupInfo.getGroupName();
            String avatar = UserContactTypeEnum.USER == typeEnum ? userInfo.getUserAvatar() : groupInfo.getGroupAvatar();
            ChatSessionUserVo chatSessionUserVo = new ChatSessionUserVo(chatSessionIdUser, contactName, helloMsg, new Date().getTime() + "", avatar, typeEnum.getType());
            map.put("chatSessionUserVo", chatSessionUserVo);
            return R.ok(UserContactTypeEnum.GROUP == typeEnum? "已加入群聊" :"已添加好友").put(CodeConstant.RESULT_MSG, map);
        }
        return R.ok("等待对方验证");
    }

    private void sendNotice(String helloMsg, TokenUserInfoDto tokenUserInfoDto, UserContactTypeEnum typeEnum, GroupInfo groupInfo, UserInfo userInfo) {
        MessageSendVo messageSendVo = new MessageSendVo();
        if(UserContactTypeEnum.GROUP == typeEnum){
            //更新群组人员数量
            groupInfoMapper.updateCurrentNumber(groupInfo.getGroupId());
            messageSendVo.setLastMessage(helloMsg);
            messageSendVo.setMessageContent(helloMsg);
            messageSendVo.setContactType(UserContactTypeEnum.GROUP.getType());
            messageSendVo.setContactName(groupInfo.getGroupName());
            messageSendVo.setContactId(groupInfo.getGroupId());
            messageSendVo.setSendUserId(tokenUserInfoDto.getUserId());
            messageSendVo.setSendUserNickName(tokenUserInfoDto.getNickName());
            messageSendVo.setAvatar(groupInfo.getGroupAvatar());
            messageSendVo.setMemberCount(groupInfo.getCurrentNumber() + 1);
            messageSendVo.setSessionId(CommonUtil.getChatSessionIdUser(new String[]{tokenUserInfoDto.getUserId(), groupInfo.getGroupId()}));
            messageSendVo.setMessageType(MessageTypeEnum.ADD_GROUP.getType());
            //发送消息
            sendMessageHandler.sendMessage(messageSendVo);
        }
        if(UserContactTypeEnum.USER == typeEnum){
            messageSendVo.setContactName(userInfo.getNickName());
            messageSendVo.setContactType(UserContactTypeEnum.USER.getType());
            messageSendVo.setContactId(userInfo.getUserId());
            messageSendVo.setSendUserId(tokenUserInfoDto.getUserId());
            messageSendVo.setSendUserNickName(tokenUserInfoDto.getNickName());
            messageSendVo.setAvatar(tokenUserInfoDto.getAvatar());
            messageSendVo.setSessionId(CommonUtil.getChatSessionIdUser(new String[]{tokenUserInfoDto.getUserId(), userInfo.getUserId()}));
            messageSendVo.setMessageType(MessageTypeEnum.ADD_FRIEND.getType());
            //发送消息
            sendMessageHandler.sendMessage(messageSendVo);
        }
    }

    public record ChatSessionUserVo(String sessionId, String contactName, String lastMessage,
                                    String lastReceiveTime, String avatar, Integer contactType
                                    ){}


    private String createCategory(String userId, UserContactCategory userContactCategory) {
        int group = userContactCategoryService.createGroup(userId, userContactCategory);
        if(group > 0){
            return userContactCategory.getCategoryId();
        }
        return null;
    }

    @Override
    public R showApplyContact() {
        TokenUserInfoDto tokenUserInfoDto = CommonUtil.getSecurityContext();
        //不查remark字段
        List<UserContactApply> userContactApplies = userContactApplyMapper.selectList(
                new LambdaQueryWrapper<UserContactApply>()
                        .select(UserContactApply.class, info -> !info.getColumn().equals("remark"))
                        .eq(UserContactApply::getReceiveUserId, tokenUserInfoDto.getUserId())
                        .or()
                        .eq(UserContactApply::getApplyUserId, tokenUserInfoDto.getUserId())
                        .orderByDesc(UserContactApply::getCreateTime)

        );
        if(userContactApplies.isEmpty()){
            return R.ok().put(CodeConstant.RESULT_MSG,Collections.emptyList());
        }
        //查询所有用户id
        List<String> allUserIds = Stream.concat(
                userContactApplies.stream().map(UserContactApply::getApplyUserId),
                userContactApplies.stream().map(UserContactApply::getReceiveUserId)
        ).distinct().toList();
        // 查询所有用户信息
        List<UserInfo> allUserInfos = userInfoMapper.selectList(new LambdaQueryWrapper<UserInfo>()
                .select(UserInfo::getUserAvatar, UserInfo::getPersonalSignature, UserInfo::getUserId, UserInfo::getNickName, UserInfo::getSex, UserInfo::getBirthday)
                .in(UserInfo::getUserId, allUserIds));
        // 将用户信息存储在Map中
        Map<String, UserInfo> userInfoMap = allUserInfos.stream()
                .collect(Collectors.toMap(UserInfo::getUserId, userInfo -> userInfo));
        // 设置用户信息
        userContactApplies.forEach(userContactApply -> {
            UserInfo applyUserInfo = userInfoMap.get(userContactApply.getApplyUserId());
            if (applyUserInfo != null) {
                userContactApply.setApplyUserInfo(applyUserInfo);
            }
            UserInfo receiveUserInfo = userInfoMap.get(userContactApply.getReceiveUserId());
            if (receiveUserInfo != null) {
                userContactApply.setReceiveUserInfo(receiveUserInfo);
            }
        });
        return R.ok().put(CodeConstant.RESULT_MSG, userContactApplies);
    }

    @Override
    @Transactional
    public R agreeApply(String applyUserId, String receiveUserId, String applyId) throws BusinessException {
        //获取当前线程
        TokenUserInfoDto tokenUserInfoDto = CommonUtil.getSecurityContext();
        if(tokenUserInfoDto.getUserId() == null || !tokenUserInfoDto.getUserId().equals(receiveUserId)){
            throw new RuntimeException("当前用户不是接收者");
        }
        UserContactApply userContactApply = userContactApplyMapper.selectOne(new LambdaQueryWrapper<UserContactApply>()
                .eq(UserContactApply::getApplyId, applyId));
        if(userContactApply == null){
            throw new BusinessException(ExceptionBizCodeEnum.NOT_FOUND_ACCOUNT);
        }
        //判断申请人Id是用户还是群组
        UserContactTypeEnum typeEnum = UserContactTypeEnum.getPrefix(applyUserId);
        if(typeEnum == null){
            throw new BusinessException(ExceptionBizCodeEnum.USER_ID_FORMAT_EXCEPTION);
        }
        //判断是否是群组
        GroupInfo groupInfo = null;
        UserInfo userInfo = null;
        if(UserContactTypeEnum.GROUP == typeEnum){
            groupInfo = groupInfoMapper.selectById(applyUserId);
            if(groupInfo == null){
                throw new BusinessException(ExceptionBizCodeEnum.GROUP_NOT_EXIST);
            }
        }else{
            userInfo = userInfoMapper.selectById(applyUserId);
            if(userInfo == null){
                throw new BusinessException(ExceptionBizCodeEnum.NOT_FOUND_ACCOUNT);
            }
        }
        //查询该申请信息
        userContactApply.setLastApplyTime(new Date());
        userContactApply.setStatus(UserContactApplyStatusEnum.AGREED.getStatus());
        //更改数据库
        int update = userContactApplyMapper.update(userContactApply, new LambdaQueryWrapper<UserContactApply>()
                        .eq(UserContactApply::getApplyId, applyId));
        if(update == 0){
            throw new BusinessException(ExceptionBizCodeEnum.NOT_FOUND_ACCOUNT);
        }
        UserContact userContact = userContactMapper.selectOne(applyUserId, tokenUserInfoDto.getUserId());
        //添加联系人
        this.addContact(applyUserId, receiveUserId, userContactApply.getContactId()
                , userContactApply.getApplyInfo(), userContactApply.getRemark(),
                userContactApply.getContactType(), userContact);
        //添加会话
        int session = chatSessionUserService.addSession(tokenUserInfoDto,
                groupInfo != null ? groupInfo : userInfo,
                userContactApply.getHelloMsg(),
                UserContactTypeEnum.GROUP == typeEnum? UserContactTypeEnum.GROUP.getType() : UserContactTypeEnum.USER.getType());
        if(session <= 0){
            throw new BusinessException(ExceptionBizCodeEnum.SESSION_ADD_FAILED);
        }
        //添加分组
        if(userContactApply.getCategoryId() != null){
            //添加到分组
            //判断是否是用户
            if(UserContactTypeEnum.USER == typeEnum){
                userContactCategoryService.addGroup(userContactApply.getCategoryId(), applyUserId, receiveUserId);
            }
        }
        if(userContactApply.getPermission() != null && Boolean.parseBoolean(userContactApply.getPermission())){
            //TODO 处理只聊天不看动态
        }
        //发送消息通知好友
        sendNotice(userContactApply.getHelloMsg(), tokenUserInfoDto, typeEnum, groupInfo, userInfo);
        return R.ok();
    }

    @Override
    public R refuseApply(String applyUserId, String receiveUserId, String applyId) throws BusinessException {
        //获取当前线程
        TokenUserInfoDto tokenUserInfoDto = CommonUtil.getSecurityContext();
        if(tokenUserInfoDto.getUserId() == null || !tokenUserInfoDto.getUserId().equals(receiveUserId)){
            throw new RuntimeException("当前用户不是接收者");
        }
        UserInfo userInfo = userInfoMapper.selectById(applyUserId);
        if(userInfo == null){
            throw new BusinessException(ExceptionBizCodeEnum.NOT_FOUND_ACCOUNT);
        }
        UserContactApply userContactApply = userContactApplyMapper.selectOne(new LambdaQueryWrapper<UserContactApply>()
                .eq(UserContactApply::getApplyId, applyId));
        if(userContactApply == null){
            throw new BusinessException(ExceptionBizCodeEnum.NOT_FOUND_ACCOUNT);
        }
        userContactApply.setLastApplyTime(new Date());
        userContactApply.setStatus(UserContactApplyStatusEnum.DECLINED.getStatus());
        //更改数据库
        int update = userContactApplyMapper.update(userContactApply, new LambdaQueryWrapper<UserContactApply>()
                .eq(UserContactApply::getApplyId, applyId));
        if(update == 0){
            throw new BusinessException(ExceptionBizCodeEnum.NOT_FOUND_ACCOUNT);
        }
        return R.ok();
    }

    @Override
    public R addContact(String applyUserId, String receiveUserId, String contactId
            , String applyInfo, String remark, Integer contactType, UserContact userContact) throws BusinessException {

        //查询群聊人数
        if(contactType.equals(UserContactTypeEnum.GROUP.getType()) && contactId != null){
            GroupInfo groupInfo = groupInfoMapper.selectById(contactId);
            if(groupInfo != null && groupInfo.getMaxNumber() >= groupInfo.getCurrentNumber()){
                throw new BusinessException(ExceptionBizCodeEnum.GROUP_MEMBER_FULL);
            }
        }
        String s = userContactService.addRemark(receiveUserId, applyUserId, remark);
        if(userContact == null){
            userContact = new UserContact();
            userContact.setUserId(applyUserId);
            userContact.setContactId(receiveUserId);
            userContact.setContactType(contactType);
            userContact.setCreateTime(new Date());
            userContact.setLastUpdateTime(new Date());
            userContact.setStatus(UserContactStatusEnum.FRIEND.getStatus());
            userContact.setRemark(s);
            //插入
            userContactMapper.insert(userContact);
        }else{
            //更新
            userContact.setLastUpdateTime(new Date());
            userContact.setRemark(s);
            userContactMapper.updateById(userContact);
        }
        return R.ok("申请成功");
    }

    @Override
    public R getAllApply(String userId) {
        //获取申请信息
        List<UserContactApply> userContactApplies = userContactApplyMapper.selectList(new LambdaQueryWrapper<UserContactApply>()
                .eq(UserContactApply::getReceiveUserId, userId)
                .or()
                .eq(UserContactApply::getApplyUserId, userId));
        //群组Ids
        List<String> groupIds = new ArrayList<>();
        //用户Ids
        List<String> userIds = new ArrayList<>();
        if(!userContactApplies.isEmpty()){
            userContactApplies.forEach(userContactApply -> {
                if(userId.equals(userContactApply.getApplyUserId())){
                    if(UserContactTypeEnum.GROUP.getType().equals(userContactApply.getContactType())){
                        groupIds.add(userContactApply.getContactId());
                    }else{
                        userIds.add(userContactApply.getContactId());
                    }
                    userContactApply.setQueryId(userContactApply.getContactId());
                }else{
                    if(UserContactTypeEnum.GROUP.getType().equals(userContactApply.getContactType())){
                        groupIds.add(userContactApply.getApplyUserId());
                    }else{
                        userIds.add(userContactApply.getApplyUserId());
                    }
                    userContactApply.setQueryId(userContactApply.getApplyUserId());
                }
            });
        }
        //异步查询
        try{
            CompletableFuture<List<GroupInfo>> listCompletableFutureGroup = CompletableFuture.supplyAsync(() -> {
                //获取详细信息
                if (!groupIds.isEmpty()) {
                    return groupInfoMapper.selectList(new LambdaQueryWrapper<GroupInfo>()
                            .select(GroupInfo::getGroupId, GroupInfo::getGroupName, GroupInfo::getGroupAvatar)
                            .in(GroupInfo::getGroupId, groupIds));
                }
                return null;
            }, threadPoolTaskExecutor);

            CompletableFuture<List<UserInfo>> listCompletableFutureUser = CompletableFuture.supplyAsync(() -> {
                if (!userIds.isEmpty()) {
                    return userInfoMapper.selectList(new LambdaQueryWrapper<UserInfo>()
                            .select(UserInfo::getUserId, UserInfo::getNickName, UserInfo::getUserAvatar)
                            .in(UserInfo::getUserId, userIds));
                }
                return null;

            }, threadPoolTaskExecutor);
            CompletableFuture.allOf(listCompletableFutureGroup, listCompletableFutureUser).join();
            List<GroupInfo> groupInfos = listCompletableFutureGroup.get();
            List<UserInfo> userInfos = listCompletableFutureUser.get();
            if(groupInfos != null){
                groupInfos.forEach(groupInfo -> {
                    userContactApplies.forEach(userContactApply -> {
                        if(userContactApply.getQueryId().equals(groupInfo.getGroupId())){
                            userContactApply.setApplyUserInfo(groupInfo);
                        }
                    });
                });
            }
            if(userInfos != null){
                userInfos.forEach(userInfo -> {
                   userContactApplies.forEach(userContactApply -> {
                       if(userContactApply.getQueryId().equals(userInfo.getUserId())){
                           UserInfoVO userInfoVO = new UserInfoVO();
                           BeanUtils.copyProperties(userInfo, userInfoVO);
                           userContactApply.setApplyUserInfo(userInfoVO);
                       }
                   });
                });
            }
        }catch (Exception e){
            log.error("查询好友申请列表失败",e);
        }
        return R.ok().put(CodeConstant.RESULT_MSG, userContactApplies);
    }
}
